#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include "structs.h"
#include "params.h"


CriptoType getCriptoType(const char * arg);
CriptoMode getCriptoMode(const char * arg);

int
getParams (int argc, char * argv[], Params *params)
{
	int c;

	static struct option long_options[] =
	{
		{"out", required_argument, NULL, 0},
		{"in", required_argument, NULL, 1},
		{"e", no_argument, NULL, 'e'},
		{"d", no_argument, NULL, 'd'},
		{"pass", required_argument, NULL, 'p'},
		{"K", required_argument, NULL, 'k'},
		{"iv", required_argument, NULL, 'i'},
		{"a", required_argument, NULL, 'a'},
		{"m", required_argument, NULL, 'm'},
		{0, 0, 0, 0}
	};
	/* getopt_long stores the option index here. */

	int option_index = 0;

	while ( (c = getopt_long_only (argc, argv, "",long_options, &option_index)) != -1 )
	{
		switch (c)
		{
			case 0:
				/* Means -out found. */
				if (optarg){
					strcpy(params->out, optarg);
				}
				break;

			case 1:
				/* Means -in found! */
				if (optarg != NULL){
					strcpy(params->in, optarg);
				}
				break;

			case 'e':
				if (params -> op == 0)
				{
					params -> op = -1;
				}
				else
				{
					params -> op = 1;
				}
				break;

			case 'd':
				if (params -> op == 1)
				{
					params -> op = -1;
				}
				else
				{
					params -> op = 0;
				}
				break;

			case 'p':
				strcpy(params->pass, optarg);
				break;

			case 'k':
				if(optarg != NULL)
				{
					strncpy(params -> key, optarg, strlen(optarg));
					params -> key[strlen(optarg)] =  '\0';
				}

				break;

			case 'i':
				if(optarg != NULL)
				{
					strncpy(params -> iv, optarg, strlen(optarg));
					params -> iv[strlen(optarg)] =  '\0';
				}
				break;

			case 'a':
				if (optarg != NULL)
				{
					params -> a = getCriptoType(optarg);
				}
				break;

			case 'm':
				if (optarg != NULL)
				{
					params -> m = getCriptoMode(optarg);
				}
				break;

			case '?':
				printf("ERROR in getopt_long\n");
				exit(-1);

			default:
				/* TODO: ver que carajo hacer aca jaja */
				abort ();
			}
	}

	/* Print any remaining command line arguments (not options). */
	if (optind < argc)
	{
		printf ("Argumento/s no reconocidos: ");
		while (optind < argc)
			printf ("%s ", argv[optind++]);
		putchar ('\n');
	}

	int good=0;
	good = validateParams(params);

	if(!good)
	{
		printf("Error en los comandos\n");
	}

	return good;
}

void
initParams(Params * params)
{
	strcpy(params -> in, "");
	strcpy(params -> out, "");
	params -> pass[0] = '\0';
	params -> iv[0] = '\0';
	params -> key[0] = '\0';
	params -> op = -1;
	params -> a = UNDEFINED;
	params -> m = NONE;
}

int
validateParams(Params * params)
{
	int passLength;

	if(params->op == -1)
	{
		return 0;
	}

	if(strlen(params->in) == 0)
	{
		return 0;
	}

	if(strlen(params->out) == 0)
	{
		return 0;
	}


	passLength = strlen(params->pass);

	/* es mas corto negar la condicion para que la combinacion de comandos validos pass || key-IV sea correcta
	 * que validar todas las posibles combinaciones incorrectas
	 */
	if ( !((passLength > 0 && params -> key[0] == '\0' && params -> iv[0] == '\0') || (passLength == 0 && (params -> key[0] != '\0' && params -> iv[0] != '\0'))
			|| (passLength == 0 && params -> key[0] != '\0' && params -> iv[0] == '\0' && params -> m == ECB)))
	{
		return 0;
	}

	if(params -> a == UNDEFINED)
	{
		return 0;
	}

	if(params -> m == NONE)
	{
		return 0;
	}


	if(params -> key[0] != '\0' && ( (strlen(params -> key) != 8 && params -> a  == DES) || (strlen(params -> key) != 16 && params -> a != DES) ))
	{
		printf("La longitud del key debe ser 8 para DES o 16 para AES\n");
		return 0;
	}

	if(params -> iv[0] != '\0' && ( (strlen(params -> iv) !=8 && params -> a == DES) || (strlen(params -> iv) !=16 && params -> a != DES) ))
	{
		printf("La longitud del vector de inicializacion debe ser 8 para DES o 16 para AES\n");
		return 0;
	}

	return 1;
}

CriptoType
getCriptoType(const char * arg)
{
	int i;
	const char * criptoNames[CRIPTOQTY] = {"aes128","aes192","aes256","des"};
	CriptoType criptotypes[CRIPTOQTY] = {AES128, AES192, AES256, DES};
	CriptoType criptotype = UNDEFINED;

	if (arg != NULL)
	{
		for (i = 0 ; i < CRIPTOQTY ; i++)
		{
			if (strncmp(arg,criptoNames[i],strlen(criptoNames[i])) == 0)
			{
				criptotype = criptotypes[i];
				break;
			}
		}
	}

	return criptotype;
}

CriptoMode
getCriptoMode(const char * arg)
{
	int i;
	const char * criptoModeNames[MODEQTY] = {"ecb","cfb","ofb","cbc"};
	CriptoMode criptomodes[MODEQTY] = {ECB,CFB,OFB,CBC};
	CriptoMode criptomode = NONE;

	if (arg != NULL)
	{
		for (i = 0 ; i < MODEQTY ; i++)
		{
			if (strncmp(arg,criptoModeNames[i],strlen(criptoModeNames[i])) == 0)
			{
				criptomode = criptomodes[i];
				break;
			}
		}
	}

	return criptomode;
}
